# src/core/domain/balance.py

from decimal import Decimal, getcontext
from typing import List, Tuple
import pandas as pd

# 设置Decimal的精度，例如30位，这足以应对绝大多数金融计算
getcontext().prec = 30

# 为了代码清晰，定义一些常量
ZERO = Decimal('0')
ONE_HUNDRED = Decimal('100')


class Balance:
    """
    一个模拟高精度保证金账户的类。

    它使用Decimal类型来处理所有与资金相关的计算，以确保准确性。
    负责跟踪所有与资金和风险相关的核心指标。
    """

    def __init__(self, initial_capital: str, leverage: str):
        """
        Args:
            initial_capital (str): 初始资金，以字符串形式提供以保证精度, e.g., "10000.00"。
            leverage (str): 杠杆倍数，以字符串形式提供, e.g., "10.0"。
        """
        # --- 初始化参数 ---
        self.initial_capital = Decimal(initial_capital)
        if self.initial_capital <= ZERO:
            raise ValueError("初始资金必须为正数。")

        self.leverage = Decimal(leverage)
        if self.leverage < Decimal('1'):
            raise ValueError("杠杆必须大于等于1。")

        # --- 核心账户指标 (全部使用Decimal) ---
        self.balance: Decimal = self.initial_capital
        self.equity: Decimal = self.initial_capital
        self.used_margin: Decimal = ZERO
        self.available_margin: Decimal = self.initial_capital
        self.margin_level: Decimal = Decimal('inf')

        # --- 日志记录 ---
        self.equity_curve: List[Tuple[pd.Timestamp, Decimal]] = [(pd.Timestamp(0), self.initial_capital)]

    def update_market_value(self, total_unrealized_pnl: Decimal, timestamp: pd.Timestamp):
        """
        由Portfolio在每个时间点调用，用最新的浮动盈亏来更新账户状态。
        """
        self.equity = self.balance + total_unrealized_pnl
        self.available_margin = self.equity - self.used_margin

        if self.used_margin > ZERO:
            self.margin_level = (self.equity / self.used_margin) * ONE_HUNDRED
        else:
            self.margin_level = Decimal('inf')

        self.equity_curve.append((timestamp, self.equity))

        # 检查并处理爆仓风险
        if self.used_margin > ZERO and self.margin_level <= ONE_HUNDRED:
            # 在真实的引擎中，这里应该抛出一个异常或事件，
            # 告诉引擎立即清算所有仓位。
            # 为了简化，我们只打印警告。
            print(f"CRITICAL WARNING ({timestamp}): MARGIN CALL! Margin Level at {self.margin_level:.2f}%.")

    def on_position_opened(self, required_margin: Decimal):
        """
        当一个新仓位（或加仓）被建立时，由Portfolio调用。
        """
        if required_margin <= ZERO:
            return
        self.used_margin += required_margin
        # 可用保证金的最终更新将在下一次 update_market_value 中完成

    def on_position_closed(self, pnl: Decimal, margin_freed: Decimal):
        """
        当一个仓位被平掉时，由Portfolio调用。
        """
        # 1. 结算已实现盈亏到余额
        self.balance += pnl
        # 2. 释放占用的保证金
        self.used_margin -= margin_freed

    def __repr__(self):
        return (
            f"Balance(equity={self.equity:.2f}, balance={self.balance:.2f}, "
            f"used_margin={self.used_margin:.2f}, available_margin={self.available_margin:.2f}, "
            f"margin_level={self.margin_level:.2f}%)"
        )
